﻿using System;
using System.Collections.Generic;

using System.Text;
using System.Windows;
using System.Collections;
using System.Windows.Input;
using Bixas.Tangibilis.Utility;

namespace Bixas.Tangibilis.Controls
{
    public class TouchUIElementAdapter<T>
        where T : UIElement, ITouchElement
    {
        private T _elementAdapted;

        public TouchUIElementAdapter(T elementAdapted)
        {
            this._elementAdapted = elementAdapted;
        }

        static TouchUIElementAdapter()
        {
            RegisterClassHandler(TouchCursorEvents.TouchCursorDownEvent, new RoutedEventHandler(TouchUIElementAdapter<T>.OnTouchCursorDownEventThunk), true);
            RegisterClassHandler(TouchCursorEvents.TouchCursorEnterEvent, new RoutedEventHandler(TouchUIElementAdapter<T>.OnTouchCursorEnterEventThunk), false);
            RegisterClassHandler(TouchCursorEvents.TouchCursorLeaveEvent, new RoutedEventHandler(TouchUIElementAdapter<T>.OnTouchCursorLeaveEventThunk), false);
            RegisterClassHandler(TouchCursorEvents.TouchCursorMoveEvent, new RoutedEventHandler(TouchUIElementAdapter<T>.OnTouchCursorMoveEventThunk), false);
            RegisterClassHandler(TouchCursorEvents.TouchCursorUpEvent, new RoutedEventHandler(TouchUIElementAdapter<T>.OnTouchCursorUpEventThunk), false);
            RegisterClassHandler(TouchCursorEvents.TouchCursorPreviewDownEvent, new RoutedEventHandler(TouchUIElementAdapter<T>.OnTouchCursorPreviewDownEventThunk), false);
            RegisterClassHandler(TouchCursorEvents.TouchCursorPreviewMoveEvent, new RoutedEventHandler(TouchUIElementAdapter<T>.OnTouchCursorPreviewMoveEventThunk), false);
            RegisterClassHandler(TouchCursorEvents.TouchCursorPreviewUpEvent, new RoutedEventHandler(TouchUIElementAdapter<T>.OnTouchCursorPreviewUpEventThunk), false);
                
        }

        public virtual void OnTouchCursorPreviewDown(object sender, RoutedEventArgs e) { }
        public virtual void OnTouchCursorPreviewMove(object sender, RoutedEventArgs e) { }
        public virtual void OnTouchCursorPreviewUp(object sender, RoutedEventArgs e) { }

        private static void OnTouchCursorDownEventThunk(object sender, RoutedEventArgs e)
        {
            CrackTranslateInput(sender as IInputElement, e as InputEventArgs);
            if (!e.Handled & sender is T)
            {
                ITouchCursorEventThunk thunk = sender as ITouchCursorEventThunk;
                if (thunk != null)
                {
                    thunk.OnTouchCursorDownThunk(sender, e);
                }
            }
        }

        private static void OnTouchCursorEnterEventThunk(object sender, RoutedEventArgs e)
        {
            CrackTranslateInput(sender as IInputElement, e as InputEventArgs);
            if (!e.Handled & sender is T)
            {
                ITouchCursorEventThunk thunk = sender as ITouchCursorEventThunk;
                if (thunk != null)
                {
                    thunk.OnTouchCursorEnterThunk(sender, e);
                }
            }
        }
        private static void OnTouchCursorLeaveEventThunk(object sender, RoutedEventArgs e)
        {
            CrackTranslateInput(sender as IInputElement, e as InputEventArgs);
            if (!e.Handled & sender is T)
            {
                ITouchCursorEventThunk thunk = sender as ITouchCursorEventThunk;
                if (thunk != null)
                {
                    thunk.OnTouchCursorLeaveThunk(sender, e);
                }
            }
        }
        private static void OnTouchCursorMoveEventThunk(object sender, RoutedEventArgs e)
        {
            CrackTranslateInput(sender as IInputElement, e as InputEventArgs);
            if (sender is T) //(!e.Handled & sender is T)
            {
                ITouchCursorEventThunk thunk = sender as ITouchCursorEventThunk;
                if (thunk != null)
                {
                    thunk.OnTouchCursorMoveThunk(sender, e);
                }
            }
        }
        private static void OnTouchCursorUpEventThunk(object sender, RoutedEventArgs e)
        {
            CrackTranslateInput(sender as IInputElement, e as InputEventArgs);
            if (!e.Handled & sender is T)
            {
                ITouchCursorEventThunk thunk = sender as ITouchCursorEventThunk;
                if (thunk != null)
                {
                    thunk.OnTouchCursorUpThunk(sender, e);
                }
            }
        }
        private static void OnTouchCursorPreviewDownEventThunk(object sender, RoutedEventArgs e)
        {
            ITouchCursorEventThunk thunk = sender as ITouchCursorEventThunk;
            if (thunk != null & sender is T)
            {
                thunk.OnTouchCursorPreviewDownThunk(sender, e);
            }
        }
        private static void OnTouchCursorPreviewMoveEventThunk(object sender, RoutedEventArgs e)
        {
            ITouchCursorEventThunk thunk = sender as ITouchCursorEventThunk;
            if (thunk != null & sender is T)
            {
                thunk.OnTouchCursorPreviewMoveThunk(sender, e);
            }
        }
        private static void OnTouchCursorPreviewUpEventThunk(object sender, RoutedEventArgs e)
        {
            ITouchCursorEventThunk thunk = sender as ITouchCursorEventThunk;
            if (thunk != null & sender is T)
            {
                thunk.OnTouchCursorPreviewUpThunk(sender, e);
            }
        }

        private static void RegisterClassHandler(RoutedEvent routedEvent, RoutedEventHandler handler, bool handledEventsToo)
        {
            EventManager.RegisterClassHandler(typeof(UIElement), routedEvent, handler, handledEventsToo);
            //EventManager.RegisterClassHandler(typeof(ContentElement), routedEvent, handler, handledEventsToo);
        }

        protected Hashtable cursorStateObjects = new Hashtable();

        protected TouchCursorState GetStateObject(int cursorId)
        {
            if (!this.cursorStateObjects.Contains(cursorId))
            {
                this.cursorStateObjects[cursorId] = new TouchCursorState(cursorId);
            }
            return (TouchCursorState)this.cursorStateObjects[cursorId];
        }

        protected void ReleaseStateObject(int cursorId)
        {
            this.cursorStateObjects.Remove(cursorId);
        }

        public T TouchElement { get { return _elementAdapted; } }
        public virtual void OnTouchCursorEnter(System.Windows.RoutedEventArgs e)
        {
            RawTouchCursorInputEventArgs args = (RawTouchCursorInputEventArgs)e;
            TouchCursorState stateObject = this.GetStateObject(args.Cursor.cursorID);
            stateObject.IsOver = true;
            this.TouchElement.IsTouchCursorOver = this.IsTouchCursorOver;
            this.TouchElement.IsTouchCursorPressed = this.IsTouchCursorPressed;
        }

        public virtual void OnTouchCursorLeave(System.Windows.RoutedEventArgs e)
        {
            RawTouchCursorInputEventArgs args = (RawTouchCursorInputEventArgs)e;
            TouchCursorState stateObject = this.GetStateObject(args.Cursor.cursorID);
            stateObject.IsClicked = false;
            stateObject.IsOver = false;
            this.TouchElement.IsTouchCursorOver = this.IsTouchCursorOver;
            this.TouchElement.IsTouchCursorPressed = this.IsTouchCursorPressed;
        }

        public virtual void OnTouchCursorUp(System.Windows.RoutedEventArgs e)
        {
            RawTouchCursorInputEventArgs args = (RawTouchCursorInputEventArgs)e;
            this.ReleaseStateObject(args.Cursor.cursorID);
            this.TouchElement.IsTouchCursorPressed = this.IsTouchCursorPressed;
        }

        public virtual void OnTouchCursorDown(System.Windows.RoutedEventArgs e)
        {
            RawTouchCursorInputEventArgs args = e as RawTouchCursorInputEventArgs;
            if (args != null)
            {
                this.GetStateObject(args.Cursor.cursorID).IsPressed = true;
                this.GetStateObject(args.Cursor.cursorID).LastPosition = new Point(args.Cursor.Left, args.Cursor.Top);
                this.TouchElement.IsTouchCursorPressed = true;
            }
        }

        public virtual void OnTouchCursorMove(System.Windows.RoutedEventArgs e)
        {
            RawTouchCursorInputEventArgs args = e as RawTouchCursorInputEventArgs;
            if (args != null)
            {
                this.GetStateObject(args.Cursor.cursorID).LastPosition = new Point(args.Cursor.Left, args.Cursor.Top);
            }
        }

        protected bool IsTouchCursorOver
        {
            get
            {
                bool flag = false;
                IEnumerator enumerator = this.cursorStateObjects.Keys.GetEnumerator();
                while (enumerator.MoveNext())
                {
                    flag |= ((TouchCursorState)this.cursorStateObjects[enumerator.Current]).IsOver;
                }
                return flag;
            }
        }

        protected bool IsTouchCursorPressed
        {
            get
            {
                bool flag = false;
                IEnumerator enumerator = this.cursorStateObjects.Keys.GetEnumerator();
                while (enumerator.MoveNext())
                {
                    flag |= (((TouchCursorState)this.cursorStateObjects[enumerator.Current]).IsPressed & ((TouchCursorState)this.cursorStateObjects[enumerator.Current]).IsOver);
                }
                return flag;
            }
        }

        private static void CrackTranslateInput(IInputElement sender, InputEventArgs e)
        {
            Phydeaux.Utilities.Dynamic<CommandManager>.Static.Procedure.Explicit<IInputElement, InputEventArgs>.CreateDelegate("TranslateInput").Invoke(sender, e);

        }
    }
}
